#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <fstream>
#include <cassert>
#include <mariadb/mysql.h>
#include <jsoncpp/json/json.h>

#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_model
{
    using namespace std;
    using namespace ns_util;
    using namespace ns_log;

    struct Question // 一道题目都有哪些属性
    {
        std::string number; // 题目编号 唯一值
        std::string title; // 标题
        std::string level; // 难度
        int cpu_limit; // 时间要求(s)
        int mem_limit; // 空间要求(kb)
        std::string desc; // 描述
        std::string header; // 预设代码
        std::string tail; // 测试用例 header + tail = 完整代码
        std::string type; // 类型
    };
    
    const std::string oj_questions = "oj_questions";
    const std::string host = "localhost";
    const std::string user_name = "wqy";
    const std::string passwd = "123456";
    const std::string db = "oj_system"; // 数据库
    const int port = 3306;

    class Model
    {
    private:
        // <题号，题目内容>
        unordered_map<string, Question> questions;
    public:
        Model() {}

        ~Model() {}

        bool QuerySQL(const std::string &sql, vector<Question> *out)
        {
            // 1. 创建mysql句柄
            MYSQL *my = mysql_init(nullptr);

            // 2. 连接数据库
            if (mysql_real_connect(my, host.c_str(), user_name.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
            {
                LOG(FATAL) << "加载题库失败! 检查题库文件是否存在" << "\n";
                return false;
            }

            // 设置编码格式
            mysql_set_character_set(my, "utf8");
            // LOG(INFO) << "数据库连接成功" << "\n";

            // 执行sql语句
            if (mysql_query(my, sql.c_str()) != 0)
            {
                LOG(WARNING) << "sql语句: \"" << sql << "\"执行错误" << "\n";
                mysql_close(my);
                return false;
            }

            // 提取并解析结果
            MYSQL_RES *res = mysql_store_result(my);
            if (res == nullptr)
            {
                LOG(WARNING) << "sql语句: \"" << sql << "\"没有返回结果" << "\n";
                mysql_close(my);
                return false;
            }

            // 解析结果
            int rows = mysql_num_rows(res);
            Question q;

            for (int i = 0; i < rows; ++i)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                // row[0] 是id
                q.number = row[1] ? row[1] : "";
                q.title = row[2] ? row[2] : "";
                q.level = row[3] ? row[3] : "";
                q.cpu_limit = row[4] ? atoi(row[4]) : 0;
                q.mem_limit = row[5] ? atoi(row[5]) : 0;
                q.desc = row[6] ? row[6] : "";
                q.header = row[7] ? row[7] : "";
                q.tail = row[8] ? row[8] : "";
                q.type = row[9] ? row[9] : "";
                out->push_back(q);
            }

            // 释放资源
            mysql_free_result(res);
            mysql_close(my);

            return true;
        }

        // 获取所有题目 | out: 输出型参数
        bool GetAllQuestions(vector<Question> *out)
        {
            std::string sql = "SELECT * FROM " + oj_questions;
            return QuerySQL(sql, out);
        }

        // 获取单个题目
        bool GetSingleQuestion(const std::string &number, Question* out)
        {
            std::string sql = "SELECT * FROM " + oj_questions + " WHERE number = '" + number + "'";

            bool res = false;
            vector<Question> ret;
            if (QuerySQL(sql, &ret))
            {
                if (ret.size() == 1)
                {
                    *out = ret[0];
                    res = true;
                }
            }
            return res;
        }
    };
}
